//
//  UIImage+SDKExtensions.swift
//  WHYUIKit
//
//  Created by Andney Jack on 2020/4/3.
//  Copyright © 2020 Creatoo. All rights reserved.
//

import Accelerate
import QuartzCore
import UIKit

// MARK: - 图片圆角

public extension UIImage {
    /// 圆形图片
    func ct_circleImage() -> UIImage? {
        guard size.width > 0 && size.height > 0 else {
            return nil
        }
        let minSize = min(size.width, size.height)
        return ct_roundedImage(radius: minSize / 2.0, size: CGSize(width: minSize, height: minSize), clipIfNeeded: true)
    }

    /// 图片圆角
    /// - Parameters:
    ///   - radius: 圆角半径
    ///   - roundingCorners: 圆角位置
    ///   - size: 图片大小
    ///   - scale: 图片比例
    ///   - clipIfNeeded: 裁剪图片以保持图片不变形
    func ct_roundedImage(radius: CGFloat, roundingCorners: UIRectCorner = .allCorners, size: CGSize = .zero, scale: CGFloat = 0.0, clipIfNeeded: Bool = false) -> UIImage? {
        let imgSize = (size.width > 0 && size.height > 0) ? size : self.size
        guard imgSize.width > 0 && imgSize.height > 0 else {
            return nil
        }

        let imgRect = CGRect(x: 0, y: 0, width: imgSize.width, height: imgSize.height)
        UIGraphicsBeginImageContextWithOptions(imgSize, false, scale)

        UIBezierPath(roundedRect: imgRect,
                     byRoundingCorners: roundingCorners,
                     cornerRadii: CGSize(width: radius, height: radius)).addClip()

        if clipIfNeeded && __CGSizeEqualToSize(self.size, imgSize) == false {
            guard let clipedImage = ct_clip(to: imgSize.height / imgSize.width) else { return nil }
            clipedImage.draw(in: imgRect)
        } else {
            draw(in: imgRect)
        }

        guard let result = UIGraphicsGetImageFromCurrentImageContext() else { return nil }

        UIGraphicsEndImageContext()

        return result
    }
}

// MARK: - 图片缩放、裁剪

public extension UIImage {
    // 获取x倍图
    func ct_getScaleImage(_ multiple: CGFloat) -> UIImage {
        guard multiple != scale && multiple >= 0.0 else {
            return self
        }
        guard size.width > 0 && size.height > 0 else {
            return self
        }

        let newSize = CGSize(width: size.width * scale / multiple, height: size.height * scale / multiple)
        UIGraphicsBeginImageContextWithOptions(newSize, false, multiple)
        draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))

        guard let result = UIGraphicsGetImageFromCurrentImageContext() else { return self }
        UIGraphicsEndImageContext()
        return result
    }

    /// 获取 @2x 图片
    func ct_get2xImage() -> UIImage {
        return ct_getScaleImage(2.0)
    }

    /// 获取 @3x 图片
    func ct_get3xImage() -> UIImage {
        return ct_getScaleImage(3.0)
    }

    /// 裁剪图片的指定区域
    func ct_clip(in rect: CGRect) -> UIImage? {
        guard size.width > 0 && size.height > 0 else {
            return nil
        }
        guard let imgRef = cgImage?.cropping(to: rect) else {
            return nil
        }
        return UIImage(cgImage: imgRef)
    }

    /// 裁剪图片至指定的宽高比
    /// - Parameter aspecRatio: 高度与宽度之比
    func ct_clip(to aspecRatio: CGFloat) -> UIImage? {
        guard size.width > 0 && size.height > 0 && aspecRatio > 0 else {
            return nil
        }

        // 图片的原始尺寸
        let srcWidth = size.width * scale
        let srcHeight = size.height * scale
        let srcScale = srcHeight / srcWidth

        if aspecRatio == srcScale { return self }

        var targetRect: CGRect
        if aspecRatio < srcScale {
            // 垂直方向的两头被裁剪掉
            targetRect = CGRect(x: 0.0, y: (srcHeight - srcWidth * aspecRatio) / 2.0, width: srcWidth, height: srcWidth * aspecRatio)
        } else {
            // 水平方向的两头被裁剪掉
            targetRect = CGRect(x: (srcWidth - srcHeight / aspecRatio) / 2.0, y: 0.0, width: srcHeight / aspecRatio, height: srcHeight)
        }

        guard let imgRef = cgImage?.cropping(to: targetRect) else { return nil }

        return UIImage(cgImage: imgRef)
    }

    // 裁剪图片至指定的大小
    func ct_clip(to targetSize: CGSize, imgScale: CGFloat = 1.0) -> UIImage? {
        guard size.width > 0 && size.height > 0 else { return nil }
        guard targetSize.width > 0 && targetSize.height > 0 else { return nil }

        if __CGSizeEqualToSize(targetSize, size) && scale == imgScale {
            return self
        }

        guard let image = ct_clip(to: targetSize.height / targetSize.width) else { return nil }

        UIGraphicsBeginImageContextWithOptions(targetSize, !ct_hasAlpha(), imgScale)
        image.draw(in: CGRect(x: 0, y: 0, width: targetSize.width, height: targetSize.height))
        guard let result = UIGraphicsGetImageFromCurrentImageContext() else { return nil }
        UIGraphicsEndImageContext()
        return result
    }

    /// 限制图片的最大尺寸
    /// - Parameters:
    ///   - maxPixel: 最大像素尺寸
    ///   - scale: 图片比例
    func ct_limitTo(maxPixel: CGFloat, scale: CGFloat = 1.0) -> UIImage {
        guard size.width > 0 && size.height > 0 else {
            return self
        }

        var imgSize = CGSize(width: size.width * scale, height: size.height * scale)

        guard imgSize.width > maxPixel || imgSize.height > maxPixel else {
            return self
        }

        if imgSize.width > imgSize.height {
            imgSize = CGSize(width: maxPixel, height: maxPixel * (imgSize.height / imgSize.width))
        } else {
            imgSize = CGSize(width: maxPixel * (imgSize.width / imgSize.height), height: maxPixel)
        }

        let hasAlpha = ct_hasAlpha()
        UIGraphicsBeginImageContextWithOptions(imgSize, !hasAlpha, scale)
        draw(in: CGRect(x: 0, y: 0, width: imgSize.width, height: imgSize.height))

        guard let result = UIGraphicsGetImageFromCurrentImageContext() else {
            UIGraphicsEndImageContext()
            return self
        }
        UIGraphicsEndImageContext()
        return result
    }

    // 图片缩放至指定的宽度
    func ct_scaleToWidth(_ targetWidth: CGFloat, canBeLarger: Bool = true, imgScale: CGFloat = 1.0) -> UIImage? {
        guard size.width > 0 && size.height > 0 else {
            return nil
        }

        var imgSize: CGSize
        if canBeLarger || targetWidth < size.width * scale {
            imgSize = CGSize(width: targetWidth, height: targetWidth * size.height / size.width)
        } else {
            imgSize = size
        }

        if __CGSizeEqualToSize(imgSize, size) && scale == imgScale {
            return self
        }

        UIGraphicsBeginImageContextWithOptions(imgSize, !ct_hasAlpha(), imgScale)
        draw(in: CGRect(x: 0, y: 0, width: imgSize.width, height: imgSize.height))

        guard let result = UIGraphicsGetImageFromCurrentImageContext() else {
            UIGraphicsEndImageContext()
            return nil
        }

        UIGraphicsEndImageContext()
        return result
    }
}

// MARK: - 图片压缩

public extension UIImage {
    /// 限制图片的字节大小
    /// - Parameters:
    ///   - maxByteLength: 最大字节长度
    ///   - maxPixel: 最大像素尺寸，大于0时有效
    func ct_limitTo(maxByteLength: Int, maxPixel: Int = 0) -> Data? {
        // 限制过小时，直接返回
        if maxByteLength <= 1024 {
            return jpegData(compressionQuality: 0.9)
        }

        // 1. 先压缩图片质量
        var compression: CGFloat = 0.95
        guard let tmpData = jpegData(compressionQuality: compression) else { return nil }
        if tmpData.count < maxByteLength {
            return tmpData
        }

        var resultImage: UIImage = ct_limitTo(maxPixel: 3000)
        var max = compression, min: CGFloat = 0.0
        var data: Data = Data()
        for _ in 0 ..< 6 {
            compression = (min + max) / 2.0
            guard let tmpData = resultImage.jpegData(compressionQuality: compression) else { continue }
            data = tmpData

            if Double(tmpData.count) < Double(maxByteLength) * 0.85 {
                min = compression
            } else if tmpData.count > maxByteLength {
                max = compression
            } else {
                break
            }
        }

        if data.count < 1 {
            return nil
        } else if data.count < maxByteLength {
            return data
        }

        guard let tmpImage = UIImage(data: data, scale: 1.0) else { return nil }
        resultImage = tmpImage

        // 2. 再压缩图片尺寸
        guard resultImage.size.width * resultImage.scale > 100.0 || resultImage.size.height * resultImage.scale > 100.0 else {
            return data
        }

        var i = 0
        while i < 6 && data.count > maxByteLength {
            let ratio = Float(maxByteLength) / Float(data.count)
            let imgSize = CGSize(width: resultImage.size.width * resultImage.scale * CGFloat(sqrtf(ratio)),
                                 height: resultImage.size.height * resultImage.scale * CGFloat(sqrtf(ratio)))

            UIGraphicsBeginImageContextWithOptions(imgSize, !ct_hasAlpha(), 1.0)
            resultImage.draw(in: CGRect(x: 0, y: 0, width: Int(imgSize.width), height: Int(imgSize.height)))

            guard let tmpImage = UIGraphicsGetImageFromCurrentImageContext() else {
                return data
            }
            resultImage = tmpImage

            UIGraphicsEndImageContext()

            guard let tmpData = resultImage.jpegData(compressionQuality: compression) else { return data }
            data = tmpData

            i += 1
        }

        return data
    }
}

// MARK: - 图片模糊

public extension UIImage {
    func ct_blurryImage() -> UIImage? {
        return ct_applyBlurryWithRadius(5, saturationDeltaFactor: 1.8, tintColor: UIColor(white: 0.1, alpha: 0.7), maskImage: nil)
    }

    func ct_applyLightEffect() -> UIImage? {
        return ct_applyBlurryWithRadius(30, saturationDeltaFactor: 1.8, tintColor: UIColor(white: 1.0, alpha: 0.3), maskImage: nil)
    }

    func ct_applyExtraLightEffect() -> UIImage? {
        return ct_applyBlurryWithRadius(20, saturationDeltaFactor: 1.8, tintColor: UIColor(white: 0.97, alpha: 0.82), maskImage: nil)
    }

    func ct_applyDarkEffect() -> UIImage? {
        return ct_applyBlurryWithRadius(20, saturationDeltaFactor: 1.8, tintColor: UIColor(white: 0.11, alpha: 0.73), maskImage: nil)
    }

    func ct_applyTintEffectWithColor(_ tintColor: UIColor) -> UIImage? {
        let effectColorAlpha: CGFloat = 0.6
        var effectColor = tintColor

        let componentCount = tintColor.cgColor.numberOfComponents
        if componentCount == 2 {
            var b: CGFloat = 0
            if tintColor.getWhite(&b, alpha: nil) {
                effectColor = UIColor(white: b, alpha: effectColorAlpha)
            }
        } else {
            var r: CGFloat = 0
            var g: CGFloat = 0
            var b: CGFloat = 0

            if tintColor.getRed(&r, green: &g, blue: &b, alpha: nil) {
                effectColor = UIColor(red: r, green: g, blue: b, alpha: effectColorAlpha)
            }
        }

        return ct_applyBlurryWithRadius(10, saturationDeltaFactor: -1.0, tintColor: effectColor, maskImage: nil)
    }

    // 图片模糊
    func ct_applyBlurryWithRadius(_ radius: CGFloat, saturationDeltaFactor: Double, tintColor: UIColor?, maskImage: UIImage?) -> UIImage? {
        if size.width < 1 || size.height < 1 {
            print("*** error: invalid size: (%.2f x %.2f). Both dimensions must be >= 1: %@", size.width, size.height, self)
            return nil
        }

        if cgImage == nil {
            print("*** error: image must be backed by a CGImage: %@", self)
            return nil
        }

        if maskImage != nil && (maskImage!.cgImage == nil) {
            print("*** error: maskImage must be backed by a CGImage: %@", maskImage!)
            return nil
        }

        let imageRect = CGRect(origin: CGPoint.zero, size: size)

        var effectImage: UIImage = self

        let hasBlur: Bool = radius > CGFloat.ulpOfOne
        let hasSaturationChange: Bool = abs(CGFloat(saturationDeltaFactor) - 1.0) > CGFloat.ulpOfOne
        let screenScale = UIScreen.main.scale

        if hasBlur || hasSaturationChange {
            UIGraphicsBeginImageContextWithOptions(size, false, screenScale)

            let effectInContext: CGContext = UIGraphicsGetCurrentContext()!

            effectInContext.scaleBy(x: 1.0, y: -1.0)
            effectInContext.translateBy(x: 0, y: -size.height)
            effectInContext.draw(cgImage!, in: imageRect)

            var effectInBuffer = vImage_Buffer()
            effectInBuffer.data = effectInContext.data
            effectInBuffer.width = vImagePixelCount(effectInContext.width)
            effectInBuffer.height = vImagePixelCount(effectInContext.height)
            effectInBuffer.rowBytes = effectInContext.bytesPerRow

            UIGraphicsBeginImageContextWithOptions(size, false, screenScale)

            let effectOutContext: CGContext = UIGraphicsGetCurrentContext()!

            var effectOutBuffer = vImage_Buffer()
            effectOutBuffer.data = effectOutContext.data
            effectOutBuffer.width = vImagePixelCount(effectOutContext.width)
            effectOutBuffer.height = vImagePixelCount(effectOutContext.height)
            effectOutBuffer.rowBytes = effectOutContext.bytesPerRow

            if hasBlur {
                let inputRadius: Double = Double(radius) * Double(screenScale)
                var radius = floor(inputRadius * 3.0 * sqrt(2 * Double.pi) / 4 + 0.5)
                let result = radius.truncatingRemainder(dividingBy: 2)

                if result != 1 {
                    radius += 1 // force radius to be odd so that the three box-blur methodology works.
                }

                var unsafePointer: UInt8 = 0
                vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, nil, 0, 0, UInt32(radius), UInt32(radius), &unsafePointer, UInt32(kvImageEdgeExtend))
                vImageBoxConvolve_ARGB8888(&effectOutBuffer, &effectInBuffer, nil, 0, 0, UInt32(radius), UInt32(radius), &unsafePointer, UInt32(kvImageEdgeExtend))
                vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, nil, 0, 0, UInt32(radius), UInt32(radius), &unsafePointer, UInt32(kvImageEdgeExtend))
            }

            var effectImageBuffersAreSwapped: Bool = false

            if hasSaturationChange {
                let s: Double = saturationDeltaFactor

                let floatingPointSaturationMatrix: [Double] = [
                    0.0722 + 0.9278 * s, 0.0722 - 0.0722 * s, 0.0722 - 0.0722 * s, 0,
                    0.7152 - 0.7152 * s, 0.7152 + 0.2848 * s, 0.7152 - 0.7152 * s, 0,
                    0.2126 - 0.2126 * s, 0.2126 - 0.2126 * s, 0.2126 + 0.7873 * s, 0,
                    0, 0, 0, 1,
                ]

                let divisor: Int32 = 256
                let matrixSize: Int = MemoryLayout.size(ofValue: floatingPointSaturationMatrix) / MemoryLayout.size(ofValue: floatingPointSaturationMatrix[0])
                var saturationMatrix = [Int16]()

                for _ in 0 ... matrixSize {
                    saturationMatrix.append(0)
                }

                for i in 0 ... matrixSize {
                    saturationMatrix[i] = Int16(roundf(Float(floatingPointSaturationMatrix[i]) * Float(divisor)))
                }

                if hasBlur {
                    vImageMatrixMultiply_ARGB8888(&effectOutBuffer, &effectInBuffer, saturationMatrix, divisor, nil, nil, UInt32(kvImageNoFlags))
                    effectImageBuffersAreSwapped = true
                } else {
                    vImageMatrixMultiply_ARGB8888(&effectInBuffer, &effectOutBuffer, saturationMatrix, divisor, nil, nil, UInt32(kvImageNoFlags))
                }
            }

            if !effectImageBuffersAreSwapped {
                effectImage = UIGraphicsGetImageFromCurrentImageContext()!
                UIGraphicsEndImageContext()
            }

            if effectImageBuffersAreSwapped {
                effectImage = UIGraphicsGetImageFromCurrentImageContext()!
                UIGraphicsEndImageContext()
            }
        }

        // 开启上下文 用于输出图像
        UIGraphicsBeginImageContextWithOptions(size, false, screenScale)

        let outputContext: CGContext = UIGraphicsGetCurrentContext()!
        outputContext.scaleBy(x: 1.0, y: -1.0)
        outputContext.translateBy(x: 0, y: -size.height)
        // 开始画底图
        outputContext.draw(cgImage!, in: imageRect)

        // 开始画模糊效果
        if hasBlur {
            outputContext.saveGState()
            if maskImage != nil {
                outputContext.draw(maskImage!.cgImage!, in: imageRect)
            } else {
                outputContext.draw(effectImage.cgImage!, in: imageRect)
            }
            outputContext.restoreGState()
        }

        // 添加颜色渲染
        if tintColor != nil {
            outputContext.saveGState()
            outputContext.setFillColor(tintColor!.cgColor)
            outputContext.fill(imageRect)
            outputContext.restoreGState()
        }

        // 输出成品，并关闭上下文
        let outputImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        return outputImage
    }
}

// MARK: - 创建图片

public extension UIImage {
    /// 创建纯色图片
    /// - Parameters:
    ///   - color: 图片的背景色
    ///   - size: 图片尺寸
    ///   - radius: 圆角半径
    ///   - scale: 图片比例
    class func ct_imageWithColor(_ color: UIColor, size: CGSize = CGSize(width: 100, height: 100), radius: CGFloat = 0.0, scale: CGFloat = 0.0) -> UIImage? {
        guard size.width > 0 && size.height > 0 else {
            return nil
        }

        let rect = CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height)

        UIGraphicsBeginImageContextWithOptions(rect.size, false, scale)

        guard let context = UIGraphicsGetCurrentContext() else {
            return nil
        }

        context.setFillColor(color.cgColor)

        if radius > 0 {
            let path = UIBezierPath(roundedRect: rect, cornerRadius: radius)
            context.addPath(path.cgPath)
            context.fillPath()
        } else {
            context.fill(rect)
        }

        let image = UIGraphicsGetImageFromCurrentImageContext()

        UIGraphicsEndImageContext()

        return image
    }

    /// 渐变图片
    /// - Parameters:
    ///   - size: 图片显示大小（实际大小跟屏幕显示比例有关）
    ///   - fromColor: 起始颜色
    ///   - toColor: 终点颜色
    ///   - radius: 圆角半径，默认无
    ///   - vertical: 是否垂直方向，默认为false
    class func ct_gradientImage(size: CGSize, fromColor: UIColor, toColor: UIColor, radius: CGFloat? = nil, vertical: Bool = false) -> UIImage? {
        UIGraphicsBeginImageContextWithOptions(size, false, 0.0)

        guard let ctx = UIGraphicsGetCurrentContext() else {
            return nil
        }

        let gl = CAGradientLayer()
        gl.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)
        gl.colors = [fromColor.cgColor, toColor.cgColor]
        if vertical {
            gl.startPoint = CGPoint(x: 0.5, y: 0.0)
            gl.endPoint = CGPoint(x: 0.5, y: 1.0)
        } else {
            gl.startPoint = CGPoint(x: 0.0, y: 0.5)
            gl.endPoint = CGPoint(x: 1.0, y: 0.5)
        }
        gl.locations = [0.0, 1.0]
        if radius != nil {
            gl.cornerRadius = radius!
        }
        gl.render(in: ctx)

        let targetImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return targetImage
    }

    /// 生成占位图
    /// - Parameters:
    ///   - size: 占位图大小
    ///   - icon: 中间的Icon图标
    ///   - iconSize: 图标大小，不指定时会按照比例显示
    ///   - fillColor: 填充色
    ///   - scale: 图片比例，默认为2倍图
    ///   - borderColor: 边框颜色
    ///   - borderWidth: 边框宽度
    class func ct_placeholderImage(size: CGSize, icon: UIImage, iconSize: CGSize = .zero, fillColor: UIColor = .white, scale: CGFloat = 2.0, borderColor: UIColor? = nil, borderWidth: CGFloat = 0.0) -> UIImage? {
        guard size.width > 0 && size.height > 0 else {
            return nil
        }
        guard icon.size.width > 0 && icon.size.height > 0 else {
            return nil
        }

        var centerIconSize: CGSize
        if iconSize.width < 1.0 || iconSize.height < 1.0 {
            let minContainerSize = min(size.width, size.height)
            var width: CGFloat = 0
            var height: CGFloat = 0

            if icon.size.width < icon.size.height {
                width = min(100, max(minContainerSize * 0.3, 20))
                height = width * icon.size.height / icon.size.width
            } else {
                height = min(100, max(minContainerSize * 0.3, 20))
                width = height * icon.size.width / icon.size.height
            }

            centerIconSize = CGSize(width: width, height: height)
        } else {
            centerIconSize = iconSize
        }

        let imgRect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
        UIGraphicsBeginImageContextWithOptions(size, true, scale)

        // 设置背景色
        guard let context = UIGraphicsGetCurrentContext() else { return nil }
        context.setFillColor(fillColor.cgColor)
        context.setBlendMode(.normal)
        context.fill(imgRect)

        // 设置边框
        if let bColor = borderColor, borderWidth > 0.0 {
            context.setStrokeColor(bColor.cgColor) // 设置边框颜色
            context.stroke(imgRect, width: borderWidth) // 设置边框宽度
            context.strokePath()
        }

        let iconRect = CGRect(x: (size.width - centerIconSize.width) / 2.0,
                              y: (size.height - centerIconSize.height) / 2.0,
                              width: centerIconSize.width,
                              height: centerIconSize.height)
        icon.draw(in: iconRect)

        guard let result = UIGraphicsGetImageFromCurrentImageContext() else { return nil }

        UIGraphicsEndImageContext()

        return result
    }
}

// MARK: - 其它方法

public extension UIImage {
    /// 判断是否为有效的图片
    func ct_isValidImg() -> Bool {
        guard size.width > 0 && size.height > 0 else {
            return false
        }
        return true
    }

    /// 判断图片是否包含透明度
    func ct_hasAlpha() -> Bool {
        guard let cgImage = self.cgImage else { return false }

        let alphaInfo = CGImageAlphaInfo(rawValue: cgImage.alphaInfo.rawValue & CGBitmapInfo.alphaInfoMask.rawValue)
        if alphaInfo == .premultipliedLast || alphaInfo == .premultipliedFirst || alphaInfo == .last || alphaInfo == .first {
            return true
        }
        return false
    }

    /// 获取灰度图片
    func ct_grayImage() -> UIImage? {
        guard let cgImage = self.cgImage else { return nil }

        let width = Int(size.width * scale)
        let height = Int(size.height * scale)

        // 创建灰度色彩空间对象，各种设备对待颜色的方式都不一样，颜色必须有一个相关的色彩空间
        let colorSpace = CGColorSpaceCreateDeviceGray()

        let bitmapInfo: UInt32 = ct_hasAlpha() ? CGImageAlphaInfo.premultipliedLast.rawValue : CGImageAlphaInfo.none.rawValue

        // 参数说明：
        // - data: 指向渲染的绘制内存的地址，
        // - bitsPerComponent: 表示内存中像素的每个组件的位数
        // - bytesPerRow: 表示每一行在内存中占的比特数
        // - space: 表示使用的颜色空间
        // - bitmapInfo: 表示是否包含alpha通道
        guard let ctx = CGContext(data: nil, width: width, height: height, bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace, bitmapInfo: bitmapInfo) else {
            return nil
        }

        // 在灰度上下文中画入图片
        ctx.draw(cgImage, in: CGRect(x: 0, y: 0, width: width, height: height))

        // 从上下文中获取并生成专为灰度的图片
        guard let result = ctx.makeImage() else { return nil }

        return UIImage(cgImage: result, scale: scale, orientation: imageOrientation)
    }

    /// 矫正图片的方向
    func ct_orientationFixedImage() -> UIImage? {
        guard imageOrientation != .up else {
            return self
        }

        guard let imageRef = self.cgImage else { return nil }

        // We need to calculate the proper transformation to make the image upright.
        // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
        var transform = CGAffineTransform.identity

        if imageOrientation == .down || imageOrientation == .downMirrored {
            transform = transform.translatedBy(x: size.width, y: size.height)
            transform = transform.rotated(by: .pi)
        } else if imageOrientation == .left || imageOrientation == .leftMirrored {
            transform = transform.translatedBy(x: size.width, y: 0)
            transform = transform.rotated(by: .pi / 2.0)
        } else if imageOrientation == .right || imageOrientation == .rightMirrored {
            transform = transform.translatedBy(x: 0, y: size.height)
            transform = transform.rotated(by: -(.pi / 2.0))
        }

        if imageOrientation == .upMirrored || imageOrientation == .downMirrored {
            transform = transform.translatedBy(x: size.width, y: 0)
            transform = transform.scaledBy(x: -1.0, y: 1.0)
        } else if imageOrientation == .leftMirrored || imageOrientation == .rightMirrored {
            transform = transform.translatedBy(x: size.height, y: 0)
            transform = transform.scaledBy(x: -1.0, y: 1.0)
        }

        let colorSpace = imageRef.colorSpace ?? CGColorSpaceCreateDeviceRGB()

        guard let context = CGContext(data: nil, width: Int(size.width * scale), height: Int(size.height * scale), bitsPerComponent: imageRef.bitsPerComponent, bytesPerRow: 0, space: colorSpace, bitmapInfo: imageRef.bitmapInfo.rawValue) else {
            return nil
        }
        context.concatenate(transform)

        switch imageOrientation {
        case .left, .leftMirrored, .right, .rightMirrored:
            context.draw(imageRef, in: CGRect(x: 0, y: 0, width: size.height * scale, height: size.width * scale))
        default:
            context.draw(imageRef, in: CGRect(x: 0, y: 0, width: size.width * scale, height: size.height * scale))
        }

        // And now we just create a new UIImage from the drawing context
        guard let cgImage = context.makeImage() else { return nil }
        return UIImage(cgImage: cgImage)
    }

    /// 解析Gif图片
    /// - Parameter url: 图片路径
    class func ct_decomposedGifImage(url: URL) -> [UIImage]? {
        guard url.isFileURL else { return nil }
        guard let gifData = try? Data(contentsOf: url) else { return nil }
        guard gifData.count > 0 else { return nil }

        guard let imgSource = CGImageSourceCreateWithData(gifData as CFData, nil) else { return nil }

        let count = CGImageSourceGetCount(imgSource)
        if count <= 1 {
            guard let animatedImage = UIImage(data: gifData) else { return nil }
            guard animatedImage.size.width > 0 && animatedImage.size.height > 0 else { return nil }
            return [animatedImage]
        } else {
            var imgFrames = [UIImage]()

            for i in 0 ..< count {
                guard let cgImage = CGImageSourceCreateImageAtIndex(imgSource, i, nil) else { continue }
                imgFrames.append(UIImage(cgImage: cgImage))
            }

            guard imgFrames.count > 0 else { return nil }
            return imgFrames
        }
    }
}
